package model.AI;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

import model.Continent;
import model.Player;
import model.Territory;
import model.TradeCard;

/**
 * This class is meant to be a set of *possibly* static methods to simply
 * collect data about specific situations taking place on the game board. The
 * methods are only called by the AI bots when they are considering making a
 * move, to aid in their judgment.
 * 
 * @author David Shefchik
 * 
 *         Update
 */
public class MapInfo {
	private static List<Territory> list;
	private static List<Player> pList;
	private static List<Continent> cList;

	/**
	 * 
	 * This method takes in a player and returns that player's most populous
	 * territory.
	 * 
	 * @param player
	 *            The player in question
	 * @return The territory that is the player's most populous
	 */
	public static Territory getPlayersLargestTerritory(Player player) {
		List<Territory> tList = getPlayersTerritories(player);
		Territory largest = tList.get(0);
		for (Territory temp : tList) {
			if (temp.getTroopNumber() > largest.getTroopNumber()) {
				largest = temp;
			}
		}
		return largest;

	}

	/**
	 *Gets a list of all the territories owned by a given player
	 * 
	 * @param player
	 *            is the player to find all his Territories.
	 * @return ArrayList contains all Territories that player has.
	 */
	public static List<Territory> listPlayerTerritory(Player player) {
		List<Territory> territories = listTerritories(player.getMap());
		Territory temp;
		for (int i = 0; i < territories.size(); i++) {
			temp = territories.get(i);
			if (temp.getRuler().getName() != player.getName()) {
				territories.remove(temp);
			}
		}
		return territories;
	}

	/**
	 * Figures out whether a given player controls a continent
	 * 
	 * @param player
	 *            The player in question
	 * @return Returns true if the player owns a continent and false if he does
	 *         not
	 */
	public static boolean ownsAContinent(Player player) {
		List<Continent> cList = player.getMap().getContinentList();
		for (Continent cont : cList) {
			if (cont.getContinentRuler() != null) {
				if (cont.getContinentRuler().equals(player)) {
					return true;
				}
			}
		}
		return false;
	}

	/**
	 * 
	 * This method returns the player with the highest number of total troops of
	 * all the players
	 * 
	 * @return The player with the highest number of total troops
	 */
	public static Player getStrongestPlayer() {
		return null;

	}

	/**
	 * 
	 * This method takes in a continent and return the total number of enemy
	 * troops on that continent
	 * 
	 * @param continent
	 *            The continent being profiled
	 * @return the number of troops contained within the continent
	 */
	public static int getEnemyTroopsOnContinent(Continent continent,
			Player player) {
		int numTroops = 0;
		List<Territory> tempList = continent.listTerritory();
		for (Territory temp : tempList) {
			if (!temp.getRuler().equals(player))
				numTroops += temp.getTroopNumber();
		}

		return numTroops;

	}

	/**
	 * This method finds out and returns the continent with the fewest number of
	 * enemy troops on it and
	 * 
	 * @return The continent with the least number of enemy troops
	 */
	public static Continent getEasiestContinent(Cyborg player) {
		Continent easiest = null;
		List<Continent> Clist = ((Player) player).getMap().listContinents();
		Collections.shuffle(Clist);
		easiest = Clist.get(0);
		for (Continent cont : Clist) {
			if (getEnemyTerritoriesOnContinent(cont, player) > 0
					&& getEnemyTerritoriesOnContinent(easiest, player) > 0)
				if (getEnemyTroopsOnContinent(cont, (Player) player)
						/ getEnemyTerritoriesOnContinent(cont, player) < getEnemyTroopsOnContinent(
						easiest, (Player) player)
						/ getEnemyTerritoriesOnContinent(easiest, player)) {
					if (!cont.conqueredContinent())
						easiest = cont;

				}

		}
		return easiest;

	}

	/**
	 * Calculates the number of enemy-owned territories on a given continent
	 * 
	 * @param cont
	 *            The continent in question
	 * @param player
	 *            the person making the request
	 * @return An integer indicating the number of enemy-owned territories on
	 *         the continent
	 */
	public static int getEnemyTerritoriesOnContinent(Continent cont,
			Cyborg player) {
		list = listTerritories(((Player) player).getMap());
		int count = 0;
		for (Territory temp : list) {
			if ((!temp.getRuler().equals(player))
					&& temp.getContinent().equals(cont)) {
				count++;
			}

		}
		return count;

	}

	/**
	 * Calculates whether a given territory has neighbors who are owned by the
	 * same player. In other words, figures out if the territory is in a cluster
	 * of territories owned by the same player.
	 * 
	 * @param terr
	 *            The territory that is being processed
	 * @param player
	 *            The owner of the territory being processed
	 * @return A boolean indicating whether the territory is clustered
	 */
	public static boolean territoryIsClustered(Territory terr, Player player) {
		list = terr.listNeighbors();
		for (Territory temp : list) {
			if (temp.getRuler().equals(player))
				return true;

		}
		return false;

	}

	/**
	 * This method finds the player with the fewest number of troops and returns
	 * that player
	 * 
	 * @return The player in the game with the fewest troops
	 */
	public static Player getWeakestPlayer(Player player) {
		List<Player> playerList = listPlayers(player.getMap());
		Player weakestPlayer = playerList.get(0);
		for (int i = 0; i < playerList.size(); i++) {
			if (playerList.get(i).getNumArmies() < weakestPlayer.getNumArmies()) {
				weakestPlayer = playerList.get(i);

			}

		}
		return weakestPlayer;

	}

	/**
	 * This method takes in a continent and finds out how many enemy troops are
	 * currently bordering that continent.
	 * 
	 * @param continent
	 *            The continent being profiled
	 * @return The number of enemy troops currently bordering that continent
	 */
	public static int getEnemyTroopsBorderingContinent(Continent continent) {
		return 0;
	}

	/**
	 * Gets a list of integers representing the number of cards every other
	 * player has in the game
	 * 
	 * 
	 * @param player
	 *            The player making the request
	 * @return
	 */
	public static List<Integer> getOtherPlayersCardNumbers(Player player) {
		List<Integer> cList = new ArrayList<Integer>();
		pList = listPlayers(player.getMap());
		for (Player temp : pList) {
			if (!temp.equals(player))
				cList.add(temp.getNumCards());

		}
		return cList;
	}

	/**
	 * This method returns a list of all the given Player's territories.
	 * 
	 * @param player
	 *            The player that owns the territories
	 * @return An ArrayList of Territories the Player owns
	 */
	public static List<Territory> getPlayersTerritories(Player player) {
		list = listTerritories(player.getMap());
		List<Territory> resultList = new ArrayList<Territory>();
		for (Territory temp : list)
			if (temp.getRuler().equals(player)) {
				resultList.add(temp);

			}

		return resultList;

	}

	/**
	 * Calculates the number of bonus troops a player is to receive at the
	 * beginning of his or her turn and adds that amount to the player's bonus.
	 * 
	 * @param player
	 *            The player who's bonus troops are to be calculated
	 */
	public static void calculateTurnBonus(Player player) {
		int total = 3;
		int territoryBonus = ((getPlayersTerritories(player).size() - 9) / 3);
		if (territoryBonus > 0) {
			total += territoryBonus;
		}

		int continentBonus = 0;

		if (ownsAContinent(player)) {
			cList = listPlayersContinents(player);
			for (Continent cont : cList) {
				continentBonus += cont.getBonusTroops();
			}

			total += continentBonus;
		}

		player.addBonus(total);

	}

	/**
	 * Figures out the weakest (troops-wise) enemy territory that is bordering a
	 * given territory.
	 * 
	 * @param player
	 *            The player who owns the territory
	 * @param territory
	 *            The territory in question
	 * @return The weakest enemy territory bordering that territory
	 */
	public static Territory getWeakestBorderingEnemyTerritory(
			Territory territory) {
		List<Territory> neighbors = getEnemyBorderingTerritories(territory);

		if (!neighbors.isEmpty()) {

		}
		int count = neighbors.get(0).getTroopNumber();
		Territory weakest = neighbors.get(0);
		for (Territory temp : neighbors) {
			if ((temp.getTroopNumber() < count)) {
				weakest = temp;
			}

		}
		return weakest;

	}

	/**
	 * Creates a list of all the enemy territories that are bordering the given
	 * territory
	 * 
	 * @param player
	 *            The player that owns the territoy
	 * @param territory
	 * @return
	 */
	public static List<Territory> getEnemyBorderingTerritories(
			Territory territory) {
		list = territory.listNeighbors();
		List<Territory> enemyNeighbors = new ArrayList<Territory>();
		for (Territory temp : list) {
			if (!temp.getRuler().equals(territory.getRuler())) {
				enemyNeighbors.add(temp);

			}
		}
		return enemyNeighbors;

	}

	/**
	 * Decides whether a given territory has enemy territories bordering it
	 * 
	 * @param player
	 *            The player who owns the territory
	 * @param territory
	 *            The territory in question
	 * @return true if yes, false if no
	 */
	public static boolean hasBorderingEnemyTerritories(Player player,
			Territory territory) {
		list = territory.listNeighbors();
		for (Territory temp : list) {
			if (!temp.getRuler().equals(player)) {
				return true;

			}
		}

		return false;
	}

	/**
	 * Lists all territories in the map
	 * 
	 * @param map
	 *            The map to be examined
	 * @return A list of all territories in the map
	 */
	public static List<Territory> listTerritories(model.Map map) {
		List<Territory> list = new ArrayList<Territory>();
		for (model.Continent cont : map.listContinents())
			for (model.Territory terr : cont.listTerritory())
				list.add(terr);

		return list;

	}

	/**
	 * Generates a list of territories that make up the outer border territories
	 * of the given continent
	 * 
	 * @param cont
	 *            The continent in question
	 * @return A list of territories that are contained in the continent and
	 *         border another continent
	 */
	public static List<Territory> getContinentBorders(Continent cont) {

		list = cont.listTerritory();
		List<Territory> newList = new ArrayList<Territory>();
		for (Territory temp : list) {
			boolean isBorder = false;
			for (Territory terr : temp.listNeighbors()) {
				if (!terr.getContinent().equals(temp.getContinent())) {
					isBorder = true;

				}

			}
			if (isBorder) {
				newList.add(temp);
			}
		}
		return newList;

	}

	/**
	 * Calculates if a given player is able to trade his/her cards
	 * 
	 * @param player
	 *            The player in question
	 * @return A boolean indicating
	 */
	public static boolean playerCanTrade(Player player) {
		List<model.TradeCard.Choice> tradeList = TradeCard.tradeList(player);
		if (tradeList.isEmpty()) {
			return false;
		}
		return true;
	}

	public static List<Continent> listPlayersContinents(Player player) {
		cList = new ArrayList<Continent>();
		if (ownsAContinent(player)) {
			for (Continent cont : player.getMap().listContinents()) {

				if (cont.conqueredContinent())
					if (cont.getContinentRuler().equals(player)) {
						cList.add(cont);
					}
			}
		}

		return cList;
	}

	/**
	 * Lists all the unowned territories (Ruler is a unique nullPlayer) \
	 * 
	 * @return A list of Territories that have zero troops on them
	 */
	public static List<Territory> listUnownedTerritories(Player player) {
		List<Territory> list = new ArrayList<Territory>();
		for (model.Continent cont : player.getMap().listContinents())
			for (model.Territory terr : cont.listTerritory())
				if (terr.getTroopNumber() == 0)
					list.add(terr);

		return list;

	}

	/**
	 * Lists all the empty continents in the map
	 * 
	 * @param player
	 *            The player making the call
	 * @return A list of continents representing all the empty (roops == 0)
	 *         continents on the gameMap
	 */
	public static List<Continent> listEmptyContinents(Player player) {
		List<Continent> list = new ArrayList<Continent>();
		for (Continent cont : player.getMap().listContinents()) {
			if (getEnemyTroopsOnContinent(cont, player) == 0) {
				list.add(cont);

			}

		}
		return list;
	}

	/**
	 * Lists all the players currently in the game
	 * 
	 * 
	 * @return A list of players that are plaiying in this game
	 */
	public static List<Player> listPlayers(model.Map map) {
		List<Player> playerList = new ArrayList<Player>();
		list = listTerritories(map);
		for (Territory temp : list) {
			if (!playerList.contains(temp.getRuler())) {
				playerList.add(temp.getRuler());
			}

		}
		return playerList;
	}

}
